# -*- coding: utf-8 -*-
from abc import ABC

import numpy as np
import pandas as pd

from entity.entity import Entity
from entity.tools import Tick

global memdb, db

symbol = ''
sd = ''
ed = ''


class DFTick(pd.DataFrame, ABC):
    """pd.DataFrame格式的Tick序列
    将索引变为int， 原 datetime 类索引变为一列
    """

    def __init__(self, data=None, columns=None, index=None):
        super(DFTick, self).__init__(data, index=index)
        if columns is None:
            columns = {'LastPrice': 'LastPrice', 'AskPrice1': 'AskPrice', 'AskVolume1': 'AskVolume',
                       'BidPrice1': 'BidPrice', 'BidVolume1': 'BidVolume', 'UpdateTime': 'Time',
                       'UpdateMillisec': 'UpdateMillisec', 'interest': 'OpenInterest', 'datetime': 'DateTime'}
        self.rename(columns=columns, inplace=True)
        # print(self.head())
        # print(self.tail())
        if data is None:
            return
        if self.index.name not in ['datetime', 'DateTime', 'Datetime']:
            self.set_index('DateTime', inplace=True, drop=False)
        elif 'DateTime' not in self.columns:
            self.index.name = 'DateTime'
            self.reset_index(inplace=True, drop=False)
            self.set_index('DateTime', inplace=True, drop=False)

    def add_data(self, data):
        # print(f'{type(data)}')
        if isinstance(data, DFTick):
            return self.append(data)
        else:
            df = DFTick(data=data)
            return self.append(df)


class Ticks(Entity):
    """pd.DataFrame格式的Tick序列
    将索引变为int， 原 datetime 类索引变为一列
    """

    def __init__(self, data=None, index_name='DateTime',
                 columns=None, period=0):
        self.data = DFTick(data=data, columns=columns)
        # self.date_index = self.data.index
        # self.data.reset_index(inplace=True, drop=False)
        # self.int_index = self.data.index

        '''Strategies'''
        self.stras = {}
        '''Indicators'''
        self.indis = {}

    @property
    def last_price(self):
        return self.data['LastPrice']

    LastPrice = last_price

    @property
    def ask_pirce(self):
        return self.data['AskPrice']

    AskPrice = ask_pirce

    @property
    def ask_volume(self):
        return self.data['AskVolume']

    AskVolume = ask_volume

    @property
    def bid_price(self):
        return self.data['BidPrice']

    BidPrice = bid_price

    @property
    def bid_volume(self):
        return self.data['BidVolume']

    BidVolume = bid_volume

    @property
    def datetime(self):
        return self.data['DateTime']

    DateTime = datetime

    def ma(self, pma=60):
        ma_name = 'ma' + str(pma)
        if ma_name in self.indis:
            return
        lp = self.last_price
        ma_value = pd.Series(lp.rolling(window=pma, min_periods=1).mean(), name=ma_name)

        self[ma_name] = ma_value
        self.indis[ma_name] = {'ma': {'pma': pma}}

        def on_tick(tick):
            price = tick.LastPrice
            ma0 = (self[ma_name][-1] * (pma - 1) + price) / pma
            self[ma_name].append(pd.Series[ma0], index=[tick.DateTime])

    def hhv(self, phhv=5):
        """"找出从 phhv 到当前的最高价"""
        lp = self.last_price

        hhv_name = 'hhv' + str(phhv)
        hhh = pd.Series(lp.rolling(window=phhv).max(), name=hhv_name)
        self[hhv_name] = hhh
        self.indis[hhv_name] = {'hhv': {'phhv': phhv}}

    def llv(self, pllv=5):
        """"找出从 pllv 到当前的最低价"""
        lp = self.last_price
        llv_name = 'llv' + str(pllv)
        llv = pd.Series(lp.rolling(window=pllv).max(), name=llv_name)

        self[llv_name] = llv
        self.indis[llv_name] = {'llv': {'pllv': pllv}}

    def cross(self, s1, s2):
        """if s1 up cross s2 return 1,else if s1 down cross s2 return -1 other 0"""
        var = np.where(s1 > s2, 1, 0)
        crs_name = ''.join(['crs', s1.name, s2.name])
        crs = pd.Series(var, index=s1.index, name=crs_name).diff(1)
        # print(type(s1))
        # print(s2.head())
        # print(s1.name, s2.name)

        self[crs_name] = crs
        self.indis[crs_name] = {'cross': [s1.name, s2.name]}

    def add_data(self, data):
        # print(data.__dict__)
        if self.data.empty:
            # if not isinstance(data, (dict, pd.DataFrame, pd.Series)):
            #     data = data.__dict__
            self.data = DFTick(data)
        else:
            # if not isinstance(data, (dict, pd.DataFrame, pd.Series)):
            #     data = data.__dict__
            self.data.add_data(data)
        # print(self.stras.keys())
        for stra in self.stras.values():
            stra.on_ticks(self)

    def add_strategy(self, strategy):
        '''add strategy '''
        self.stras[strategy.id] = strategy
        if self.data.empty:
            return
        strategy.on_ticks(self)

    def add_indicator(self, indicator):
        ''' add indicator '''
        self.indis[indicator.name] = indicator

    def on_tick_update(self, tick):
        # print(self.data.tail(1))
        # print(type(tick))
        df = DFTick(data=tick.__dict__, index=[tick.DateTime])
        self.data.add_data(df)
        data =Tick(data=tick.__dict__)
        # print(data)
        for ind in self.indis:
            ind_cls = self.__getattribute__(self.indis[ind].keys()[0])
            params = self.indis[ind].values()[0]
            ind_cls.on_tick(data, **params)

        for stra in self.stras:
            self.stras[stra].on_tick(data)

    def plot(self):
        """"""
        self.last_price.plot.line()

    def plot_indi(self, indi_name):
        if indi_name in self.indis:
            self[indi_name].plot.line()

    def plot_mark(self, indi_name, marker=None, diff_num=2):
        if not marker:
            marker = ['+', '-']
            if diff_num == 3:
                marker = ['+', '=', '-']
        color = ['red', 'green']
        if diff_num == 3:
            color = ['red', 'yellow', 'green']
        indi = self[indi_name]
        lp = self[self[indi_name] != 0].last_price

        # self.plot.scatter()


# t = Tick()
# c0 = t.c
# h0 = t.h
# l0 = t.l
# i0 = t.i

# if __name__ == '__main__':
#     # from dbhelper.read_data_from_mongodb import get_ticks
#     from data.data_server import get_ticks_df
#     from config.iconfig import bq_cfg
#     from _datetime import datetime, timedelta
#
#     mc = bq_cfg.db
#     ed = datetime.now().strftime('%Y%m%d')
#     sd = (datetime.now() - timedelta(days=1)).strftime('%Y%m%d')
#     symbol = 'ag1912'
#
#     data = get_ticks_df(symbol, sd, ed, mc=mc)
#     if data.empty:
#         exit()
#     print(data.describe())
#     # print(data.columns)
#     # print(data.index.name)
#     dft = Ticks()
#     dft.add_data(data)
#     print(dft.data)
#     dft.ma(60)
#     dft.ma(300)
#     dft.cross(dft['ma60'], dft['ma300'])
#     print(dft.__dict__.keys())
#
#     # print(l)
